package com.eedi.framework.permission.service;


import com.eedi.framework.permission.controller.sys.vo.role.SysRolePageReq;
import com.eedi.framework.permission.controller.sys.vo.role.SysRoleSaveReq;
import com.eedi.framework.permission.controller.sys.vo.role.SysRoleSimpleResp;
import com.eedi.framework.permission.controller.sys.vo.role.SysRoleUpReq;
import com.eedi.framework.common.enums.CommonStatusEnum;
import com.eedi.framework.common.pojo.PageResult;
import com.eedi.framework.permission.controller.sys.vo.menu.SysMenuListReq;
import com.eedi.framework.permission.controller.sys.vo.SysDeptDataPermissionRespDTO;
import com.eedi.framework.permission.controller.sys.vo.menu.SysMenuSaveReq;
import com.eedi.framework.permission.controller.sys.vo.role.*;
import com.eedi.framework.permission.dal.dataobject.SysMenuDO;
import com.eedi.framework.permission.dal.dataobject.SysRoleDO;
import com.eedi.framework.permission.enums.SysDataScopeEnum;

import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import static java.util.Collections.singleton;

/**
 * 权限 Service 接口
 * <p>
 * 提供用户-角色、角色-菜单、角色-部门的关联权限处理
 *
 * @author 永聚长青源码
 */
public interface SysPermissionService {

    /**
     * 判断是否有权限，任一一个即可
     *
     * @param userId      用户编号
     * @param permissions 权限
     * @return 是否
     */
    boolean hasAnyPermissions(String userId, String... permissions);

    /**
     * 判断是否有角色，任一一个即可
     *
     * @param roles 角色数组
     * @return 是否
     */
    boolean hasAnyRoles(String userId, String... roles);

    // ========== 角色-菜单的相关方法  ==========

    /**
     * 设置角色菜单
     *
     * @param roleId  角色编号
     * @param menuIds 菜单编号集合
     */
    void assignRoleMenu(String roleId, Set<String> menuIds);
    /**
     * 移除角色菜单
     *
     * @param roleId  角色编号
     * @param menuIds 菜单编号集合
     */
    void removeRoleMenu(String roleId, Set<String> menuIds);
    /**
     * 处理角色删除时，删除关联授权数据
     *
     * @param roleId 角色编号
     */
    void processRoleDeleted(String roleId);

    /**
     * 处理菜单删除时，删除关联授权数据
     *
     * @param menuId 菜单编号
     */
    void processMenuDeleted(String menuId);

    /**
     * 获得角色拥有的菜单编号集合
     *
     * @param roleId 角色编号
     * @return 菜单编号集合
     */
    default Set<String> getRoleMenuListByRoleId(String roleId) {
        return getRoleMenuListByRoleId(singleton(roleId));
    }

    /**
     * 获得角色们拥有的菜单编号集合
     *
     * @param roleIds 角色编号数组
     * @return 菜单编号集合
     */
    Set<String> getRoleMenuListByRoleId(Collection<String> roleIds);

    /**
     * 获得拥有指定菜单的角色编号数组，从缓存中获取
     *
     * @param menuId 菜单编号
     * @return 角色编号数组
     */
    Set<String> getMenuRoleIdListByMenuIdFromCache(String menuId);

    // ========== 用户-角色的相关方法  ==========

    /**
     * 设置用户角色
     *
     * @param userId  角色编号
     * @param roleIds 角色编号集合
     */
    void assignUserRole(String userId, Set<String> roleIds);

    /**
     * 处理用户删除时，删除关联授权数据
     *
     * @param userId 用户编号
     */
    void processUserDeleted(String userId);

    /**
     * 获得拥有多个角色的用户编号集合
     *
     * @param roleIds 角色编号集合
     * @return 用户编号集合
     */
    Set<String> getUserRoleIdListByRoleId(Collection<String> roleIds);

    /**
     * 获得用户拥有的角色编号集合
     *
     * @param userId 用户编号
     * @return 角色编号集合
     */
    Set<String> getUserRoleIdListByUserId(String userId);

    /**
     * 获得用户拥有的角色编号集合，从缓存中获取
     *
     * @param userId 用户编号
     * @return 角色编号集合
     */
    Set<String> getUserRoleIdListByUserIdFromCache(String userId);

    // ========== 用户-部门的相关方法  ==========

    /**
     * 设置角色的数据权限
     *
     * @param roleId           角色编号
     * @param dataScope        数据范围
     * @param dataScopeDeptIds 部门编号数组
     */
    void assignRoleDataScope(String roleId, SysDataScopeEnum dataScope, Set<String> dataScopeDeptIds);

    /**
     * 获得登陆用户的部门数据权限
     *
     * @param userId 用户编号
     * @return 部门数据权限
     */
    SysDeptDataPermissionRespDTO getDeptDataPermission(String userId);


    /**
     * 创建角色
     *
     * @param createReqVO 创建角色信息
     * @return 角色编号
     */
    String createRole(@Valid SysRoleSaveReq createReqVO);

    /**
     * 更新角色
     *
     * @param updateReqVO 更新角色信息
     */
    void updateRole(@Valid SysRoleUpReq updateReqVO);

    /**
     * 删除角色
     *
     * @param roleId 角色编号
     */
    void deleteRole(String roleId);

    /**
     * 更新角色状态
     *
     * @param roleId 角色编号
     * @param status 状态
     */
    void updateRoleStatus(String roleId, CommonStatusEnum status);

    /**
     * 设置角色的数据权限
     *
     * @param roleId 角色编号
     * @param dataScope 数据范围
     * @param dataScopeDeptIds 部门编号数组
     */
    void updateRoleDataScope(String roleId, SysDataScopeEnum dataScope, Set<String> dataScopeDeptIds);

    /**
     * 获得角色
     *
     * @param roleId 角色编号
     * @return 角色
     */
    SysRoleDO getRole(String roleId);

    /**
     * 获得角色，从缓存中
     *
     * @param roleId 角色编号
     * @return 角色
     */
    SysRoleDO getRoleFromCache(String roleId);

    /**
     * 获得角色列表
     *
     * @param roleIds 角色编号数组
     * @return 角色列表
     */
    List<SysRoleDO> getRoleList(Collection<String> roleIds);

    /**
     * 获得角色数组，从缓存中
     *
     * @param roleIds 角色编号数组
     * @return 角色数组
     */
    List<SysRoleDO> getRoleListFromCache(Collection<String> roleIds);

    /**
     * 获得角色列表
     *
     * @param statuses
     * @return
     */
    List<SysRoleDO> getRoleListByStatus(Collection<CommonStatusEnum> statuses);

    /**
     * 获得所有角色列表
     *
     * @return 角色列表
     */
    List<SysRoleDO> getRoleList();

    /**
     * 获得角色分页
     *
     * @param reqVO 角色分页查询
     * @return 角色分页结果
     */
    PageResult<SysRoleDO> getRolePage(SysRolePageReq reqVO);

    /**
     * 判断角色编号数组中，是否有管理员
     *
     * @param roleIds 角色编号数组
     * @return 是否有管理员
     */
    boolean hasAnySuperAdmin(Collection<String> roleIds);

    /**
     * 校验角色们是否有效。如下情况，视为无效：
     * 1. 角色编号不存在
     * 2. 角色被禁用
     *
     * @param roleIds 角色编号数组
     */
    void validateRoleList(Collection<String> roleIds);

    /**
     * 创建菜单
     *
     * @param createReqVO 菜单信息
     * @return 创建出来的菜单编号
     */
    String createMenu(SysMenuSaveReq createReqVO);

    /**
     * 更新菜单
     *
     * @param updateReqVO 菜单信息
     */
    void updateMenu(SysMenuSaveReq updateReqVO);

    /**
     * 删除菜单
     *
     * @param sysMenuId 菜单编号
     */
    void deleteMenu(String sysMenuId);

    /**
     * 获得所有菜单列表
     *
     * @return 菜单列表
     */
    List<SysMenuDO> getMenuList();

    /**
     * 基于租户，筛选菜单列表
     * 注意，如果是系统租户，返回的还是全菜单
     *
     * @param reqVO 筛选条件请求 VO
     * @return 菜单列表
     */
    List<SysMenuDO> getMenuListByTenant(SysMenuListReq reqVO);

    /**
     * 筛选菜单列表
     *
     * @param reqVO 筛选条件请求 VO
     * @return 菜单列表
     */
    List<SysMenuDO> getMenuList(SysMenuListReq reqVO);

    /**
     * 获得权限对应的菜单编号数组
     *
     * @param permission 权限标识
     * @return 数组
     */
    List<String> getMenuIdListByPermissionFromCache(String permission);

    /**
     * 获得菜单
     *
     * @param sysMenuId 菜单编号
     * @return 菜单
     */
    SysMenuDO getMenu(String sysMenuId);

    /**
     * 获得菜单数组
     *
     * @param sysMenuIds 菜单编号数组
     * @return 菜单数组
     */
    List<SysMenuDO> getMenuList(Collection<String> sysMenuIds);

    /**
     * 获取管理员类型账号数量
     * @return 数量
     */
    Long countAdmin();

    /**
     * 根据系统用户ID获取角色列表
     * @param sysUserId 用户ID
     * @return 角色列表
     */
    List<SysRoleSimpleResp> getBySysUserId(String sysUserId);
}
